﻿/*
* Copyright (c) 2010-2012 Tesla Engine Group
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

using System;

namespace Tesla.Content {
    /// <summary>
    /// Parameter class for model loading.
    /// </summary>
    public class ModelLoaderParameters : LoaderParameters {
        //Vertex options
        private bool _swapWindingOrder;
        private bool _flipUVs;
        private float _scale;
        private float _xAngle;
        private float _yAngle;
        private float _zAngle;

        //Normal options
        private NormalGeneration _normalGen;
        private float _creaseAngle;
        private bool _generateTangentBasis;

        //Material options
        private ImageLoaderParameters _imageParameters;
        private String _texturePath;
        private String _userMaterialFile;
        private bool _preferLitMaterials;
        private bool _importLights;
        private bool _materialNamesCorrespondToGeometry;

        /// <summary>
        /// Gets or sets if winding order should be swapped. If true,
        ///  the vertex data is swapped. Default is false.
        /// </summary>
        public bool SwapWindingOrder {
            get {
                return _swapWindingOrder;
            }
            set {
                _swapWindingOrder = value;
            }
        }

        /// <summary>
        /// Gets or sets if UV coordinates should be flipped. If true, they're
        /// flipped. Default is false.
        /// </summary>
        public bool FlipUVCoordinates {
            get {
                return _flipUVs;
            }
            set {
                _flipUVs = value;
            }
        }

        /// <summary>
        /// Gets or sets the model scale, this is baked into the vertex data. Default is 1.0f.
        /// </summary>
        public float Scale {
            get {
                return _scale;
            }
            set {
                _scale = value;
            }
        }

        /// <summary>
        /// Gets or sets the angle in degrees the model should be rotated about the x-axis. This
        /// will be baked into the vertex data. Default is zero.
        /// </summary>
        public float XAxisRotation {
            get {
                return _xAngle;
            }
            set {
                _xAngle = value;
            }
        }

        /// <summary>
        /// Gets or sets the angle in degrees the model should be rotated about the y-axis. This
        /// will be baked into the vertex data. Default is zero.
        /// </summary>
        public float YAxisRotation {
            get {
                return _yAngle;
            }
            set {
                _yAngle = value;
            }
        }

        /// <summary>
        /// Gets or sets the angle in degrees the model should be rotated about the z-axis. This
        /// will be baked into the vertex data. Default is zero.
        /// </summary>
        public float ZAxisRotation {
            get {
                return _zAngle;
            }
            set {
                _zAngle = value;
            }
        }

        /// <summary>
        /// Gets or sets the enumeration value that dictates how vertex normals are generated,
        /// if enabled. Default is NormalGeneration.None.
        /// </summary>
        public NormalGeneration NormalGeneration {
            get {
                return _normalGen;
            }
            set {
                _normalGen = value;
            }
        }

        /// <summary>
        /// Gets or sets the angle in degrees used when crease normals are to be generated. Default is 66 degrees.
        /// </summary>
        public float CreaseAngle {
            get {
                return _creaseAngle;
            }
            set {
                _creaseAngle = value;
            }
        }

        /// <summary>
        /// Gets or sets if tangents and binormals should be generated. Default is false. At least one set of
        /// textures coordinates and vertex normals must be present for the tangent basis to be generated.
        /// </summary>
        public bool GenerateTangentBasis {
            get {
                return _generateTangentBasis;
            }
            set {
                _generateTangentBasis = value;
            }
        }

        /// <summary>
        /// Gets or sets if the model should prefer using the default content's lit materials, over non-lit materials.
        /// Default is true.
        /// </summary>
        public bool PreferLitMaterials {
            get {
                return _preferLitMaterials;
            }
            set {
                _preferLitMaterials = value;
            }
        }

        /// <summary>
        /// Gets or sets if lights should be imported alongside with the model. The default is false.
        /// </summary>
        public bool ImportLights {
            get {
                return _importLights;
            }
            set {
                _importLights = value;
            }
        }

        /// <summary>
        /// Gets or sets the image parameters for texture loading.
        /// </summary>
        public ImageLoaderParameters TextureParameters {
            get {
                return _imageParameters;
            }
            set {
                _imageParameters = value;
                if(value == null) {
                    _imageParameters = new ImageLoaderParameters();
                }
            }
        }

        /// <summary>
        /// Gets or sets the material file to load instead of the loader's defaults. If null, then
        /// the engine's standard materials are used. This is null by default.
        /// </summary>
        public String UserMaterialFile {
            get {
                return _userMaterialFile;
            }
            set {
                _userMaterialFile = value;
            }
        }

        /// <summary>
        /// Gets or sets if the materials in a user material file should be applied
        /// to geometries that correspond to their names (e.g. material named "geom-box-01" is applied to
        /// geometry called "geom-box-01"). Default is false.
        /// 
        /// If false and multiple materials are present in a material file, only the first material
        /// is used.
        /// </summary>
        public bool MaterialNamesCorrespondToGeometry {
            get {
                return _materialNamesCorrespondToGeometry;
            }
            set {
                _materialNamesCorrespondToGeometry = value;
            }
        }

        /// <summary>
        /// Gets or sets the path the loader should search for textures in. By default this is null, which means
        /// the loader will look in the paths specified by the model file.
        /// </summary>
        public String TexturePath {
            get {
                return _texturePath;
            }
            set {
                _texturePath = value;
            }
        }

        /// <summary>
        /// Initializes a new ModelLoaderParameter class set to parameter defaults.
        /// </summary>
        public ModelLoaderParameters() {
            _swapWindingOrder = false;
            _flipUVs = false;
            _xAngle = 0;
            _yAngle = 0;
            _zAngle = 0;

            _normalGen = NormalGeneration.None;
            _creaseAngle = 66.0f;
            _generateTangentBasis = false;

            _imageParameters = new ImageLoaderParameters();
            _preferLitMaterials = true;
            _texturePath = null;
            _userMaterialFile = null;
            _materialNamesCorrespondToGeometry = false;
            _importLights = false;
        }

        /// <summary>
        /// Validates loader parameters.
        /// </summary>
        /// <returns>
        /// True if parameters are valid.
        /// </returns>
        public override bool ValidateParameters() {
            if(_generateTangentBasis && (_normalGen == NormalGeneration.None)) {
                return false;
            }

            return true;
        }

        /// <summary>
        /// Serializes the object and writes it to the output.
        /// </summary>
        /// <param name="output">Savable Output</param>
        public override void Write(ISavableWriter output) {
            base.Write(output);
            output.WriteEnum<NormalGeneration>("NormalGeneration", _normalGen);
            output.Write("CreaseAngle", _creaseAngle);
            output.Write("GenerateTangentBasis", _generateTangentBasis);
            output.Write("FlipUVCoordinates", _flipUVs);
            output.Write("SwapWindingOrder", _swapWindingOrder);
            output.Write("Scale", _scale);
            output.Write("XAxisRotation", _xAngle);
            output.Write("YAxisRotation", _yAngle);
            output.Write("ZAxisRotation", _zAngle);
            output.Write("UserMaterialFile", _userMaterialFile);
            output.Write("MaterialNamesCorrespondToGeometry", _materialNamesCorrespondToGeometry);
            output.Write("PreferLitMaterials", _preferLitMaterials);
            output.Write("ImportLights", _importLights);
            output.WriteSavable<ImageLoaderParameters>("ImageLoaderParameters", _imageParameters);
            output.Write("TexturePath", _texturePath);
        }

        /// <summary>
        /// Deserializes the object and populates it from the input.
        /// </summary>
        /// <param name="input">Savable input</param>
        public override void Read(ISavableReader input) {
            base.Read(input);
            _normalGen = input.ReadEnum<NormalGeneration>();
            _creaseAngle = input.ReadSingle();
            _generateTangentBasis = input.ReadBoolean();
            _swapWindingOrder = input.ReadBoolean();
            _flipUVs = input.ReadBoolean();
            _scale = input.ReadSingle();
            _xAngle = input.ReadSingle();
            _yAngle = input.ReadSingle();
            _zAngle = input.ReadSingle();
            _userMaterialFile = input.ReadString();
            _materialNamesCorrespondToGeometry = input.ReadBoolean();
            _preferLitMaterials = input.ReadBoolean();
            _importLights = input.ReadBoolean();
            _imageParameters = input.ReadSavable<ImageLoaderParameters>();
            _texturePath = input.ReadString();
        }
    }
}
